#ifndef __TASK_H__
#define __TASK_H__

#include "libs/types.h"
#include "kernel/memory/memory.h"
#include "kernel/smp/cpu.h"
#include "kernel/interrupt/interrupt.h"
#include "libs/queue.h"
#include "kernel/vfs/vfs.h"
#define KERNEL_CS 	(0x08)
#define	KERNEL_DS 	(0x10)

#define	USER_CS		(0x28)
#define USER_DS		(0x30)


// stack size 32K
#define STACK_SIZE 32768

#define INIT_STACK_SIZE (STACK_SIZE * 3)


#define TASK_FILE_MAX 0x10

#define TASK_SPACE_SIZE 0x00007fffffffffff


struct TSS;

extern TSS init_tss[MAX_CPU];

extern char _text;
extern char _etext;
extern char _data;
extern char _edata;
extern char _rodata;
extern char _erodata;
extern char _bss;
extern char _ebss;
extern char _end;

extern void ret_from_intr();



#define TASK_RUNNING		(1 << 0)
#define TASK_INTERRUPTIBLE	(1 << 1)
#define	TASK_UNINTERRUPTIBLE	(1 << 2)
#define	TASK_ZOMBIE		(1 << 3)	
#define	TASK_STOPPED		(1 << 4)





#define PF_KTHREAD	(1 << 0)
#define NEED_SCHEDULE (1UL << 1)
#define PF_VFORK (1UL << 2)









//任务栈空间和任务结构  联合体
union task_union
{
	uint64_t stack[STACK_SIZE * 3 / sizeof(uint64_t)];
}__attribute__((aligned (8)));	//8Bytes align



class task;




#define GET_CURRENT			\
	"movq	%rsp,	%rbx	\n\t"	\
	"andq	$-32768,%rbx	\n\t"

#define Switch_To(prev,next) \
    do{							\
    __asm__ __volatile__ (	"pushq	%%rbp	\n\t"	\
                "pushq	%%rax	\n\t"	\
                "pushq	%%rbx	\n\t"	\
                "pushq	%%rcx	\n\t"	\
                "pushq	%%rdx	\n\t"	\
                "pushq	%%rdi	\n\t"	\
                "pushq	%%rsi	\n\t"	\
                "pushq	%%r8	\n\t"	\
                "pushq	%%r9	\n\t"	\
                "pushq	%%r10	\n\t"	\
                "pushq	%%r11	\n\t"	\
                "pushq	%%r12	\n\t"	\
                "pushq	%%r13	\n\t"	\
                "pushq	%%r14	\n\t"	\
                "pushq	%%r15	\n\t"	\
                "pushq	%%rax	\n\t"	\
                "movq  %%es, %%rax	\n\t"	\
                "xchgq	%%rax, (%%rsp)	\n\t"	\
                "pushq	%%rax	\n\t"	\
                "movq  %%ds, %%rax	\n\t"	\
                "xchgq	%%rax, (%%rsp)	\n\t"	\
                "pushq	%%rax	\n\t"	\
                "movq  %%fs, %%rax	\n\t"	\
                "xchgq	%%rax, (%%rsp)	\n\t"	\
                "pushq	%%rax	\n\t"	\
                "movq  %%gs, %%rax	\n\t"	\
                "xchgq	%%rax, (%%rsp)	\n\t"	\
                "pushfq\n\t"	\
                "movq	%%rsp,	(%0)	\n\t"	\
                "movq	(%2),	%%rsp	\n\t"	\
                "leaq	1f(%%rip),	%%rax	\n\t"	\
                "movq	%%rax,	(%1)	\n\t"	\
                "pushq	(%3)		\n\t"	\
                "jmp	_ZN11taskmanager8SwitchToEP4taskS1_	\n\t"	\
                "1:	\n\t"	\
                "popfq	\n\t"	\
                "popq	%%rax	\n\t"	\
                "movq  %%rax,%%gs 	\n\t"	\
                "popq	%%rax	\n\t"	\
                "movq  %%rax,%%fs 	\n\t"	\
                "popq	%%rax	\n\t"	\
                "movq  %%rax,%%ds 	\n\t"	\
                "popq	%%rax	\n\t"	\
                "movq   %%rax,%%es	\n\t"	\
                "popq	%%r15	\n\t"	\
                "popq	%%r14	\n\t"	\
                "popq	%%r13	\n\t"	\
                "popq	%%r12	\n\t"	\
                "popq	%%r11	\n\t"	\
                "popq	%%r10	\n\t"	\
                "popq	%%r9	\n\t"	\
                "popq	%%r8	\n\t"	\
                "popq	%%rsi	\n\t"	\
                "popq	%%rdi	\n\t"	\
                "popq	%%rdx	\n\t"	\
                "popq	%%rcx	\n\t"	\
                "popq	%%rbx	\n\t"	\
                "popq	%%rax	\n\t"	\
                "popq	%%rbp	\n\t"	\
                :		\
                :"c"(&prev->thread->rsp),"d"(&prev->thread->rip),"r"(&next->thread->rsp),"r"(&next->thread->rip),"D"(prev),"S"(next)	\
                :"memory"		\
                );			\
    }while(0);



// #define Switch_To(prev,next) \
//     do{							\
//     __asm__ __volatile__ (	"pushq	%%rbp	\n\t"	\
//                 "pushq	%%rax	\n\t"	\
//                 "movq	%%rsp,	(%0)	\n\t"	\
//                 "movq	(%2),	%%rsp	\n\t"	\
//                 "leaq	1f(%%rip),	%%rax	\n\t"	\
//                 "movq	%%rax,	(%1)	\n\t"	\
//                 "pushq	(%3)		\n\t"	\
//                 "jmp	_ZN11taskmanager8SwitchToEP4taskS1_	\n\t"	\
//                 "1:	\n\t"	\
//                 "popq	%%rax	\n\t"	\
//                 "popq	%%rbp	\n\t"	\
//                 "xchg %%bx,%%bx \n\t"  \
//                 :		\
//                 :"c"(&prev->thread->rsp),"d"(&prev->thread->rip),"r"(&next->thread->rsp),"r"(&next->thread->rip),"D"(prev),"S"(next)	\
//                 :"memory"		\
//                 );			\
//     }while(0);






uint64_t init(unsigned long arg);

class taskmemory
{
private:


public:
    pml4t_t *pgd;	//page table point
	uint64_t start_code,end_code;
	uint64_t start_data,end_data;
	uint64_t start_rodata,end_rodata;
    uint64_t start_bss,end_bss;
	uint64_t start_brk,end_brk;
	uint64_t start_stack;
    taskmemory(/* args */);
    ~taskmemory();
};





class thread
{
private:


public:
    uint64_t rsp0;	//in tss

	uint64_t rip;
	uint64_t rsp;	

	uint64_t fs;
	uint64_t gs;

	uint64_t cr2;
	uint64_t trap_nr;
	uint64_t error_code;
    thread(uint64_t rsp0, uint64_t rip, uint64_t rsp, uint64_t fs, uint64_t gs, uint64_t cr2, uint64_t trap_nr,uint64_t error_code);
    thread();
    ~thread();
};





class task
{
    private:
        

       
    public:
        List list;
        int64_t vrunTime;
        volatile int64_t state;
        //自旋锁数量
        int64_t preemptCount; 
        uint64_t flags;
        int64_t cpuId;
        File* fileHandle[TASK_FILE_MAX];
        class taskmemory *mm;
        class thread *thread;

        uint64_t addr_limit;	/*0x0000,0000,0000,0000 - 0x0000,7fff,ffff,ffff user*/
                        /*0xffff,8000,0000,0000 - 0xffff,ffff,ffff,ffff kernel*/

        int64_t pid;

        int64_t counter;

        int64_t signal;

        int64_t priority;

        task* parent;

        task(/* args */);

        ~task();
};

class CpuSchedule
{

public:
    Queue<task> taskQueue;
	uint64_t taskRuningCount;
    int64_t cpuExecTaskJiffies;
    CpuSchedule(uint64_t taskCount,int64_t slice);
    ~CpuSchedule();
};



class taskmanager
{
private:
    /* data */
	taskmemory* init_mm;
	thread* init_thread;


public:

    task* init_task[MAX_CPU];
    task* currentTask[MAX_CPU];
    //所有进程
    Queue<task> taskQueue;
    uint64_t pidCount;
    CpuSchedule* schedules[MAX_CPU];
    static taskmanager* taskm;
    taskmanager(/* args */);
    ~taskmanager();
    void SetTSS64(unsigned long rsp0,unsigned long rsp1,unsigned long rsp2,unsigned long ist1,unsigned long ist2,unsigned long ist3,
    unsigned long ist4,unsigned long ist5,unsigned long ist6,unsigned long ist7);
    void taskInit();
    volatile void static SwitchTo(task* pre, task* next);
    unsigned long do_fork(StackFrame * regs, unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size);
    int kernel_thread(uint64_t (* fn)(unsigned long), unsigned long arg, unsigned long flags);
    void initTaskSchedule();
    void initIdleTask();
    
    void shcedule();
    task* getNextScheduleTask();
    void addTaskToScheduleQueue(task*);
    task* getTaskByPid(uint64_t pid);




    inline void wakeupProcess(task* tsk);
    uint64_t copyFlags(uint64_t cloneFlags,task* tsk);
    uint64_t copyFiles(uint64_t cloneFlags,task* tsk);
    uint64_t copyMm(uint64_t cloneFlags,task* tsk);
    uint64_t copyThread(uint64_t cloneFlags,uint64_t stackStart,uint64_t stackSize,task* task,StackFrame* regs);
    
    void exitFiles(task* tsk);
    void exitMm(task* tsk);
    void exitThread(task* tsk);


    File* openExecFile(char* path);


};






#define TASKMANAGER \
taskmanager::taskm


//获取堆栈基地址
inline	task* get_current()
{
	task* current = NULL;

	    current = TASKMANAGER->currentTask[getAPICID()];

    
	return current;
}

#define current get_current()

#define preempt_enable()		\
do					\
{					\
    current->preemptCount--; \
}while(0)

#define preempt_disable()		\
do					\
{					\
	current->preemptCount++;	\
}while(0)



inline void Switch_Mm(task* prev,task* next)
{
    __asm__ __volatile__ ("movq %0,%%cr3 \n\t"::"r"(next->mm->pgd):"memory");
}


#endif